"""
衍生品仓位档位模块
获取全部仓位档位对应信息，包括最高可开杠杆倍数
"""
import time
from typing import Dict, List, Optional
from datetime import datetime, timedelta
from loguru import logger

try:
    import okx.PublicData as PublicData
except ImportError:
    logger.warning("okx SDK未安装，请运行: pip install okx")
    PublicData = None


class PositionTiersManager:
    """衍生品仓位档位管理器"""
    
    # 限速配置：10次/2s
    RATE_LIMIT_REQUESTS = 10
    RATE_LIMIT_WINDOW = 2.0  # 秒
    
    def __init__(self, sandbox: bool = True):
        """
        初始化衍生品仓位档位管理器
        
        Args:
            sandbox: 是否使用模拟盘，True=模拟盘(1)，False=实盘(0)
        """
        if PublicData is None:
            raise ImportError("okx SDK未安装，请运行: pip install okx")
        
        self.sandbox = sandbox
        flag = "1" if sandbox else "0"
        
        # 初始化OKX公共数据API
        self.public_api = PublicData.PublicAPI(flag=flag)
        
        # 限速控制
        self.request_times: List[float] = []  # 请求时间戳列表
        
        # 数据缓存
        self.position_tiers_cache: Dict[str, List[Dict]] = {}  # cache_key -> tiers_data
        self.cache_expire_time: Dict[str, datetime] = {}  # cache_key -> expire_time
        self.cache_duration = timedelta(hours=1)  # 缓存1小时
        
        logger.info(f"衍生品仓位档位管理器已初始化 (模式: {'模拟盘' if sandbox else '实盘'})")
    
    def _check_rate_limit(self):
        """
        检查并执行限速
        限速规则：10次/2s (IP)
        """
        now = time.time()
        
        # 移除2秒前的请求记录
        self.request_times = [t for t in self.request_times 
                             if now - t < self.RATE_LIMIT_WINDOW]
        
        # 如果达到限速上限，等待
        if len(self.request_times) >= self.RATE_LIMIT_REQUESTS:
            oldest_request = self.request_times[0]
            wait_time = self.RATE_LIMIT_WINDOW - (now - oldest_request)
            
            if wait_time > 0:
                logger.debug(f"触发限速，等待 {wait_time:.2f} 秒")
                time.sleep(wait_time)
                # 重新计算
                now = time.time()
                self.request_times = [t for t in self.request_times 
                                     if now - t < self.RATE_LIMIT_WINDOW]
        
        # 记录本次请求
        self.request_times.append(now)
    
    def get_position_tiers(self, inst_type: str, td_mode: str,
                          uly: Optional[str] = None,
                          inst_family: Optional[str] = None,
                          inst_id: Optional[str] = None,
                          tier: Optional[str] = None,
                          use_cache: bool = True) -> List[Dict]:
        """
        获取衍生品仓位档位
        
        Args:
            inst_type: 产品类型
                - MARGIN: 币币杠杆
                - SWAP: 永续合约
                - FUTURES: 交割合约
                - OPTION: 期权
            td_mode: 保证金模式
                - cross: 全仓
                - isolated: 逐仓
            uly: 标的指数，如 BTC-USD
            inst_family: 交易品种，如 BTC-USD
            inst_id: 产品ID，如 BTC-USD-SWAP
            tier: 指定档位，如 1
            use_cache: 是否使用缓存
            
        Returns:
            仓位档位信息列表，每个档位包含以下字段：
            - instType: 产品类型
            - instId: 产品ID
            - uly: 标的指数
            - instFamily: 交易品种
            - tier: 档位
            - minSz: 最小持仓量
            - maxSz: 最大持仓量
            - mmr: 维持保证金率
            - imr: 初始保证金率
            - maxLever: 最大杠杆倍数
            - optMgnFactor: 期权保证金系数（仅期权）
            - quoteMaxLoan: 计价币最大可借（仅币币杠杆）
            - baseMaxLoan: 交易币最大可借（仅币币杠杆）
        """
        # 生成缓存键
        cache_key = f"{inst_type}_{td_mode}_{uly}_{inst_family}_{inst_id}_{tier}"
        
        # 检查缓存
        if use_cache and cache_key in self.position_tiers_cache:
            expire_time = self.cache_expire_time.get(cache_key)
            if expire_time and datetime.now() < expire_time:
                logger.debug(f"从缓存获取仓位档位: {cache_key}")
                return self.position_tiers_cache[cache_key]
        
        # 执行限速检查
        self._check_rate_limit()
        
        try:
            # 构建请求参数
            params = {
                "instType": inst_type,
                "tdMode": td_mode
            }
            if uly:
                params["uly"] = uly
            if inst_family:
                params["instFamily"] = inst_family
            if inst_id:
                params["instId"] = inst_id
            if tier:
                params["tier"] = tier
            
            logger.info(f"获取衍生品仓位档位: {params}")
            result = self.public_api.get_position_tiers(**params)
            
            # 检查响应
            if result.get("code") != "0":
                error_msg = result.get("msg", "未知错误")
                logger.error(f"获取仓位档位失败: {error_msg}")
                raise RuntimeError(f"API错误: {error_msg}")
            
            # 提取数据
            data_list = result.get("data", [])
            logger.info(f"获取仓位档位成功: {len(data_list)} 个档位")
            
            # 更新缓存
            if use_cache:
                self.position_tiers_cache[cache_key] = data_list
                self.cache_expire_time[cache_key] = datetime.now() + self.cache_duration
            
            return data_list
            
        except Exception as e:
            logger.error(f"获取仓位档位异常: {e}")
            raise
    
    def get_position_tiers_details(self, inst_id: str, td_mode: str) -> List[Dict]:
        """
        获取指定产品的仓位档位详细信息（包含格式化数据）
        
        Args:
            inst_id: 产品ID
            td_mode: 保证金模式 (cross/isolated)
            
        Returns:
            档位详细信息列表
        """
        # 从inst_id推断产品类型
        if "-SWAP" in inst_id:
            inst_type = "SWAP"
        elif "-" in inst_id and inst_id.count("-") >= 2:
            parts = inst_id.split("-")
            if len(parts) >= 3 and len(parts[2]) == 6 and parts[2].isdigit():
                inst_type = "FUTURES"
            else:
                inst_type = "OPTION"
        else:
            inst_type = "MARGIN"
        
        tiers = self.get_position_tiers(
            inst_type=inst_type,
            td_mode=td_mode,
            inst_id=inst_id
        )
        
        details_list = []
        for tier_data in tiers:
            details = {
                "inst_id": inst_id,
                "inst_type": tier_data.get("instType"),
                "td_mode": td_mode,
                "tier": int(tier_data.get("tier", 0)),
                "min_size": float(tier_data.get("minSz", 0)),
                "max_size": float(tier_data.get("maxSz", 0)),
                "mmr": float(tier_data.get("mmr", 0)),  # 维持保证金率
                "imr": float(tier_data.get("imr", 0)),  # 初始保证金率
                "max_leverage": float(tier_data.get("maxLever", 0)),
            }
            
            # 期权特有字段
            if inst_type == "OPTION":
                details["opt_mgn_factor"] = float(tier_data.get("optMgnFactor", 0))
            
            # 币币杠杆特有字段
            if inst_type == "MARGIN":
                details["quote_max_loan"] = float(tier_data.get("quoteMaxLoan", 0))
                details["base_max_loan"] = float(tier_data.get("baseMaxLoan", 0))
            
            details_list.append(details)
        
        return details_list
    
    def get_max_leverage_for_size(self, inst_id: str, td_mode: str, 
                                  position_size: float) -> Dict:
        """
        根据持仓量获取最大可用杠杆
        
        Args:
            inst_id: 产品ID
            td_mode: 保证金模式
            position_size: 持仓量
            
        Returns:
            包含最大杠杆和档位信息的字典
        """
        tiers = self.get_position_tiers_details(inst_id, td_mode)
        
        # 找到对应的档位
        for tier in tiers:
            if tier["min_size"] <= position_size <= tier["max_size"]:
                return {
                    "inst_id": inst_id,
                    "position_size": position_size,
                    "tier": tier["tier"],
                    "max_leverage": tier["max_leverage"],
                    "mmr": tier["mmr"],
                    "imr": tier["imr"],
                    "tier_range": f"[{tier['min_size']}, {tier['max_size']}]"
                }
        
        # 如果超出所有档位范围
        if tiers:
            last_tier = tiers[-1]
            if position_size > last_tier["max_size"]:
                return {
                    "inst_id": inst_id,
                    "position_size": position_size,
                    "tier": last_tier["tier"],
                    "max_leverage": last_tier["max_leverage"],
                    "mmr": last_tier["mmr"],
                    "imr": last_tier["imr"],
                    "tier_range": f"[{last_tier['min_size']}, {last_tier['max_size']}]",
                    "warning": "持仓量超出最大档位范围"
                }
        
        raise ValueError(f"无法找到对应档位: {inst_id}, 持仓量={position_size}")
    
    def get_swap_position_tiers(self, uly: str, td_mode: str = "cross") -> List[Dict]:
        """
        获取永续合约仓位档位
        
        Args:
            uly: 标的指数
            td_mode: 保证金模式，默认全仓
            
        Returns:
            永续合约仓位档位列表
        """
        return self.get_position_tiers("SWAP", td_mode, uly=uly)
    
    def get_futures_position_tiers(self, uly: str, td_mode: str = "cross") -> List[Dict]:
        """
        获取交割合约仓位档位
        
        Args:
            uly: 标的指数
            td_mode: 保证金模式，默认全仓
            
        Returns:
            交割合约仓位档位列表
        """
        return self.get_position_tiers("FUTURES", td_mode, uly=uly)
    
    def compare_leverage_across_modes(self, inst_id: str, position_size: float) -> Dict:
        """
        比较全仓和逐仓模式下的杠杆倍数
        
        Args:
            inst_id: 产品ID
            position_size: 持仓量
            
        Returns:
            比较结果字典
        """
        cross_info = self.get_max_leverage_for_size(inst_id, "cross", position_size)
        isolated_info = self.get_max_leverage_for_size(inst_id, "isolated", position_size)
        
        return {
            "inst_id": inst_id,
            "position_size": position_size,
            "cross_mode": {
                "max_leverage": cross_info["max_leverage"],
                "tier": cross_info["tier"],
                "mmr": cross_info["mmr"],
            },
            "isolated_mode": {
                "max_leverage": isolated_info["max_leverage"],
                "tier": isolated_info["tier"],
                "mmr": isolated_info["mmr"],
            },
            "leverage_diff": cross_info["max_leverage"] - isolated_info["max_leverage"]
        }
    
    def clear_cache(self, cache_key: Optional[str] = None):
        """
        清除缓存
        
        Args:
            cache_key: 缓存键，如果为None则清除所有缓存
        """
        if cache_key:
            if cache_key in self.position_tiers_cache:
                del self.position_tiers_cache[cache_key]
            if cache_key in self.cache_expire_time:
                del self.cache_expire_time[cache_key]
            logger.info(f"已清除 {cache_key} 的缓存")
        else:
            self.position_tiers_cache.clear()
            self.cache_expire_time.clear()
            logger.info("已清除所有仓位档位缓存")
    
    def get_cache_stats(self) -> Dict:
        """
        获取缓存统计信息
        
        Returns:
            缓存统计字典
        """
        total_cached = len(self.position_tiers_cache)
        valid_cached = sum(1 for key in self.position_tiers_cache.keys()
                          if key in self.cache_expire_time and
                          datetime.now() < self.cache_expire_time[key])
        
        return {
            "total_cached": total_cached,
            "valid_cached": valid_cached,
            "expired_cached": total_cached - valid_cached,
            "cache_duration_hours": self.cache_duration.total_seconds() / 3600,
        }


# 便捷函数
def get_position_tiers(inst_type: str, td_mode: str, sandbox: bool = True, **kwargs) -> List[Dict]:
    """
    便捷函数：获取衍生品仓位档位
    
    Args:
        inst_type: 产品类型 (MARGIN/SWAP/FUTURES/OPTION)
        td_mode: 保证金模式 (cross/isolated)
        sandbox: 是否使用模拟盘
        **kwargs: 其他参数传递给get_position_tiers
        
    Returns:
        仓位档位信息列表
    """
    manager = PositionTiersManager(sandbox=sandbox)
    return manager.get_position_tiers(inst_type, td_mode, **kwargs)


def get_max_leverage_for_size(inst_id: str, td_mode: str, position_size: float, 
                              sandbox: bool = True) -> Dict:
    """
    便捷函数：根据持仓量获取最大可用杠杆
    
    Args:
        inst_id: 产品ID
        td_mode: 保证金模式
        position_size: 持仓量
        sandbox: 是否使用模拟盘
        
    Returns:
        包含最大杠杆和档位信息的字典
    """
    manager = PositionTiersManager(sandbox=sandbox)
    return manager.get_max_leverage_for_size(inst_id, td_mode, position_size)


def compare_leverage_across_modes(inst_id: str, position_size: float, 
                                  sandbox: bool = True) -> Dict:
    """
    便捷函数：比较全仓和逐仓模式下的杠杆倍数
    
    Args:
        inst_id: 产品ID
        position_size: 持仓量
        sandbox: 是否使用模拟盘
        
    Returns:
        比较结果字典
    """
    manager = PositionTiersManager(sandbox=sandbox)
    return manager.compare_leverage_across_modes(inst_id, position_size)
